/**
 * The original work is distributed by the Mathjax (apache-2.0)
 * https://github.com/mathjax/mathjax-v3
 * https://github.com/mathjax/mj3-demos-node/blob/master/mj3-tex2html
 * 
 */
 import { mathjax } from 'mathjax-full/js/mathjax';
 import { TeX } from 'mathjax-full/js/input/tex';
 import { CHTML } from 'mathjax-full/js/output/chtml';
 import { liteAdaptor } from 'mathjax-full/js/adaptors/liteAdaptor';
 import { AllPackages } from 'mathjax-full/js/input/tex/AllPackages';
 import { RegisterHTMLHandler } from 'mathjax-full/js/handlers/html.js';
 
 /**
  * @template T
  * @param  {T|undefined} param 
  * @param  {T}           defaultParam 
  * @return {T}
  */
 function useParam(param:any, defaultParam:any) {
   return param !== undefined ? param : defaultParam;
 }
 
 /**
  * @typedef { import('./tex2html').Tex2HtmlConfig } Tex2HtmlConfig
  */
 
 const MATHJAX_DEFAULT_FONT_URL = 'https://cdn.jsdelivr.net/npm/mathjax-full@3/es5/output/chtml/fonts/woff-v2';
 
 /**
  * tex2html is a module which converts tex string into Common HTML format.
  * The exported function initializes the engine and returns two functions.
  * One converts the input. Another function creates CSS content.
  * 
  * The initial parameters are used to configure the engine. 
  * You can also pass parameters when converting. This parameters are used over
  * initial parameters, but some parameters are ignored.
  * 
  * @param {Partial<Tex2HtmlConfig>=} opts 
  */
export function createTEX2HTML (opts?:any) {
   // set default parameters
   opts = opts || {};
   opts.inline = opts.inline || false;
   opts.em = opts.em || 16;
   opts.ex = opts.ex || 8;
   opts.width = opts.width || 80 * 16;
   opts.tex = opts.tex || {};
   opts.tex.packages = opts.tex.packages || AllPackages.sort().join(', ');
   opts.chtml = opts.chtml || {};
   opts.chtml.scale = opts.chtml.scale || 1.21; // magic # chosen which looks better.
   opts.chtml.fontURL = opts.chtml.fontURL || MATHJAX_DEFAULT_FONT_URL;
   opts.chtml.adaptiveCSS = opts.chtml.adaptiveCSS || true;
   opts.chtml.exFactor = opts.chtml.exFactor || (opts.ex / opts.em);
 
   // derive some parameters
   if (typeof opts.tex.packages == 'string') {
     opts.tex.packages = opts.tex.packages.split(/\s*,\s*/);
   }
 
   //
   // set up mathjax and conversion function
   //
   const adaptor = liteAdaptor();
   RegisterHTMLHandler(adaptor);
   const tex = new TeX(opts.tex);
   const chtml = new CHTML(opts.chtml);
   const html = mathjax.document('', {
     InputJax: tex,
     OutputJax: chtml
   });
 
   /**
    * Function which converts input 
    * @param {string}          tex      TeX equation
    * @param {Tex2HtmlConfig}   param    conversion parameters
    */
   const Convert = (tex:any, param:any) => {
     param = param || opts;
     const node = html.convert(tex || '', {
       display: !useParam(param.inline, opts.inline),
       em: useParam(param.em, opts.em),
       ex: useParam(param.ex, opts.ex),
       containerWidth: useParam(param.width, opts.width),
       scale: 1.0,
     })
     return adaptor.outerHTML(node);
   }
 
   const GetCSS = () => {
       // @ts-ignore
     return adaptor.textContent(chtml.styleSheet(html));
   }
 
   return {
     convert: Convert,
     getCSS: GetCSS,
   }
 };
